/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package montecarlo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static java.lang.Math.max;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import model.Options;

/**
 *
 * @author Gautier & Sacha
 */
public class MonteCarloMT {
    private static int z;
    private static int i;
    public double sum;
    public double computeMonteCarlo(String flag, Options opt, final int nbSteps, int nbSimulations)
            throws InterruptedException, ExecutionException {
        final int numberOfCores = Runtime.getRuntime().availableProcessors();
        System.out.println(numberOfCores);
        final double blockingCoefficient = 0.9;
        final int poolSize = (int) (numberOfCores / (1 - blockingCoefficient));

        ///////////////////////////////////////////;
        double T = opt.getT();
        double v = opt.getV();
        double b = opt.getB();
        final double X = opt.getX();
        double r = opt.getR();
        final double S = opt.getS();
        double dt;


        final double Drift;
        final double vSqrdt;
        double avg;
        dt = T / nbSteps;
        Drift = (b - v * v / 2) * dt;
        vSqrdt = v * java.lang.Math.sqrt(dt);

        if (flag.equals("Call")) {
            z = 1;
        } else if (flag.equals("Put")) {
            z = -1;
        } else {
            System.exit(-1);
        }
        //////////////////////////////////////
        
         List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
        for (i = 0; i < nbSimulations; i++ ) {
            partitions.add(new Callable<Double>() {
                private double St;
                private double res;
                public Double call() throws Exception {//Fonction de base
                
                St = MonteCarlo.OneSimulation(S,Drift,vSqrdt,nbSteps);
                res = res + max(z * (St - X), 0);
                return res;
                }
            }
            );
        }

        final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);
        final List<Future<Double>> valueOfRuns = executorPool.invokeAll(partitions, 10000, TimeUnit.SECONDS);
        //Moyenne de fin de truc
        for (Future<Double> valueOfARun : valueOfRuns) {
           sum += valueOfARun.get();
        }

        executorPool.shutdown();
        return java.lang.Math.exp(-r * T) * (sum / nbSimulations);
    }
}
